package cn.chendd.example.jpa.nativequery;

import cn.chendd.example.jpa.nativequery.annotions.QueryResult;
import cn.chendd.example.jpa.nativequery.enums.QueryColumnScope;
import com.google.common.collect.Maps;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.hibernate.WrongClassException;
import org.hibernate.query.ParameterMetadata;
import org.hibernate.query.internal.NativeQueryImpl;
import org.hibernate.transform.Transformers;
import org.hibernate.type.AnyType;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.Type;
import org.springframework.lang.NonNull;

import javax.jws.soap.SOAPBinding;
import javax.lang.model.UnknownEntityException;
import javax.lang.model.type.UnknownTypeException;
import java.lang.annotation.AnnotationTypeMismatchException;
import java.lang.invoke.WrongMethodTypeException;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @author chendd
 * @date 2020/4/1
 */
public class SQLQueryBean extends SQLQuery {

    @Override
    protected Object execute(SqlParameter sqlParameter) {
        NativeQueryImpl nativeQuery = super.getEntityManager().createNativeQuery(sqlParameter.getSql()).unwrap(NativeQueryImpl.class);
        List<Object> paramList = sqlParameter.getParamList();
        ParameterMetadata pmd = nativeQuery.getParameterMetadata();
        int parameterCount = pmd.getParameterCount();
        for(int i=0 ; i < parameterCount; i++){
            nativeQuery.setParameter(i + 1 , paramList.get(i));
        }
        QueryResult queryResult = super.getQuery().resultSet();
        Class<?> mappingClass = super.getMethod().getReturnType();
        if(List.class.isAssignableFrom(mappingClass)){
            ParameterizedType type = (ParameterizedType) super.getMethod().getGenericReturnType();
            String typeName = type.getTypeName();
            String className = StringUtils.substringBetween(typeName , "<" , ">");
            try {
                mappingClass = Class.forName(className);
            } catch (ClassNotFoundException e) {
                throw new WrongMethodTypeException(String.format("Return value generic type error for method：[%s]" , className));
            }
        }
        nativeQuery.setResultTransformer(Transformers.aliasToBean(mappingClass));
        Map<String , ? extends Type> dataMap = QueryColumnScope.getColumnMapping(mappingClass , queryResult.include());
        Set<? extends Map.Entry<String, ? extends Type>> entrySet = dataMap.entrySet();
        for (Map.Entry<String , ? extends Type> entry : entrySet) {
            nativeQuery.addScalar(entry.getKey() , entry.getValue());
        }
        return super.queryResult(nativeQuery);
    }

}
